package cn.yr.clock.interceptor;

import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.NotFoundException;
import org.springframework.boot.SpringBootVersion;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;

/**
 * <p>Title: ActionReportInterceptor</p>
 * <p>Description: controller请求信息打印拦截器</p>
 *
 * @author sliver
 * @email 18142611739@163.com
 * @date 2021-11-28 11:10
 */
@Component
public class ActionReportInterceptor implements HandlerInterceptor {
    protected static final String title = "\nSpringBoot-" + SpringBootVersion.getVersion() + " action report -------- ";
    protected static final ThreadLocal<SimpleDateFormat> sdf = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    protected static int maxOutputLengthOfParaValue = 512;
    protected static boolean reportAfterInvocation = true;
    /**
     * 定位方法所在行数，依赖于java assist
     */
    protected static boolean locateMethodLineNumber = true;
    private static String[] DEFAULT_INCLUDE_PATH = new String[]{"/**"};
    private static String[] DEFAULT_EXCLUDE_PATH = new String[]{"/**/*.css", "/**/*.js", "/**/*.html", "/**/*.jpg", "/**/*.png", "/**/*.ico,/**/*.woff2"};
    private static ClassPool pool = ClassPool.getDefault();

    public String[] getIncludePath() {
        return DEFAULT_INCLUDE_PATH;
    }

    public String[] getExcludePath() {
        return DEFAULT_EXCLUDE_PATH;
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!reportAfterInvocation && handler instanceof HandlerMethod) {
            report(request, response, (HandlerMethod) handler);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (reportAfterInvocation && handler instanceof HandlerMethod) {
            report(request, response, (HandlerMethod) handler);
        }
    }

    public void report(HttpServletRequest request, HttpServletResponse response, HandlerMethod handler) {
        StringBuilder sb = new StringBuilder(title).append(sdf.get().format(new Date())).append(" --------------------------\n");
        sb.append("Url         : ").append(request.getMethod()).append(" ").append(request.getRequestURI()).append("\n");
        Class<?> cc = handler.getBeanType();
        int lineNumber = getLineNumber(handler, cc);
        sb.append("Controller  : ").append(cc.getName()).append(".(").append(cc.getSimpleName()).append(".java:" + lineNumber + ")");
        sb.append("\nMethod      : ").append(handler.getMethod().getName()).append("\n");
        Enumeration<String> e = request.getParameterNames();
        if (e.hasMoreElements()) {
            sb.append("Parameter   : ");
            while (e.hasMoreElements()) {
                String name = e.nextElement();
                String[] values = request.getParameterValues(name);
                if (values.length == 1) {
                    sb.append(name).append("=");
                    if (values[0] != null && values[0].length() > maxOutputLengthOfParaValue) {
                        sb.append(values[0].substring(0, maxOutputLengthOfParaValue)).append("...");
                    } else {
                        sb.append(values[0]);
                    }
                } else {
                    sb.append(name).append("[]={");
                    for (int i = 0; i < values.length; i++) {
                        if (i > 0) {
                            sb.append(",");
                        }
                        sb.append(values[i]);
                    }
                    sb.append("}");
                }
                sb.append("  ");
            }
            sb.append("\n");
        }
        sb.append("--------------------------------------------------------------------------------\n");
        System.out.println(sb.toString());
    }

    private int getLineNumber(HandlerMethod handler, Class<?> cc) {
        int lineNumber = 1;
        if (locateMethodLineNumber) {
            try {
                lineNumber = pool.get(cc.getName()).getDeclaredMethod(handler.getMethod().getName()).getMethodInfo().getLineNumber(0);
            } catch (NotFoundException e) {
            }
        }
        return lineNumber;
    }
}
